package com.bms.common;

import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import com.bms.common.Param.ScopeType;
import com.bms.entity.Log;
import com.bms.entity.Role;
import com.bms.entity.SensitiveWord;
import com.bms.entity.User;
import com.bms.service.LogService;

/**
 * 日志处理的切面
 * 
 * @author Lan
 */
@Aspect
@Component
public class LogHandler {

	@Resource
	private LogService logService;

	/**
	 * 定义共用方法切入点
	 * 
	 * @author Lan
	 */
	@Pointcut("execution(public * *(..))")
	public void inPublicMethod() {
	}

	/**
	 * 定义Controller方法切入点
	 * 
	 * @author Lan
	 */
	@Pointcut("execution(* com.bms.controller..*.*(..))")
	public void inControllerLayer() {
	}

	/**
	 * 定义DAO层方法切入点
	 * 
	 * @author Lan
	 */
	@Pointcut("execution(* com.bms.dao..*.*(..))")
	public void inDAOLayer() {
	}

	/**
	 * 定义Service层方法切入点
	 * 
	 * @author Lan
	 */
	@Pointcut("execution(* com.bms.service..*.*(..))")
	public void inServiceLayer() {
	}

	/**
	 * 定义总切入点
	 * 
	 * @author Lan
	 */
	@Pointcut("inPublicMethod() && (inDAOLayer() || inServiceLayer())")
	public void supportAOP() {
	}

	@SuppressWarnings("unchecked")
	@AfterReturning(pointcut = "@annotation(cLog)", returning = "retVal")
	public void doAfter(JoinPoint jp, CustomLog cLog, Object retVal) {
		Logger logger = Logger.getLogger(jp.getTarget().getClass());

		// 操作内容
		StringBuilder logDesc = new StringBuilder(cLog.desc());
		String operator = "";
		
		// 方法中的所有参数
		Object[] args = jp.getArgs();
		
		logDesc.append("[");
		for (Object arg : args) {
			if (arg instanceof User) {// 新增、修改用户、修改个人信息
				logDesc = getLogDesc(logDesc, (User) arg);
			} else if (arg instanceof SensitiveWord) { // 新增敏感字
				SensitiveWord sw = (SensitiveWord) arg;
				logDesc.append("敏感字=" + sw.getWord());
			} else if (arg instanceof String) {
				logDesc.append(arg);
			} else if (arg instanceof Boolean) {
				String methodName = jp.getSignature().getName();
				if ("setPublish".equals(methodName)) {
					if ((Boolean) arg) {
						logDesc.append("自动");
					} else {
						logDesc.append("手动");
					}
				} else if ("getNewFiles".equals(methodName)) {
					if ((Boolean) arg) {
						logDesc.append("清空所有待（初/二/三）审中的文件");
					} else if (!((Boolean) arg)) {
						logDesc
						.append("保留待（初/二/三）审中的文件，同时待（二/三）审文件的审核级别退回初级");
					}
				}
				
			} else if (arg instanceof HttpServletRequest) {
				Param[] paramList = cLog.params();
				HttpServletRequest request = (HttpServletRequest) arg;
				for (Param parameter : paramList) {
					ScopeType scope = parameter.scope();
					
					// 参数值来自 request.getParameter
					if (scope == ScopeType.REQUEST) {
						String value = request.getParameter(parameter
								.name());
						logDesc.append(parameter.nameDesc() + value);
					} else if (scope == ScopeType.SESSION){
						Object sessionObj = request.getSession().getAttribute(parameter
								.name());
						if(sessionObj instanceof User){
							operator = ((User)sessionObj).getUsername();
						}
					}
				}
			} else if (arg instanceof HttpSession){
				Param[] paramList = cLog.params();
				HttpSession session = (HttpSession) arg;
				for (Param parameter : paramList) {
					ScopeType scope = parameter.scope();
					
					// 参数值来自 session.getAttribute(..)
					if (scope == ScopeType.SESSION){
						Object sessionObj = session.getAttribute(parameter
								.name());
						if(sessionObj instanceof User){
							operator = ((User)sessionObj).getUsername();
						}
					}
				}
			}
		}
		
		logDesc.append(" ]");
		
		// 操作结果。返回值为Map类型（json）
		if (retVal instanceof Map<?, ?>) {
			Map<String, String> map = (Map<String, String>) retVal;
			if ("success".equals(map.get("msg"))) {
				logDesc.append(" [操作成功]");
			} else {
				logDesc.append(" [操作失败][原因：" + map.get("msg") + "]");
			}
		}
		
		// 日志入库
		Log logEntity = new Log();
		logEntity.setLogUser(operator);
		logEntity.setDescription(logDesc.toString());
		
		logService.save(logEntity);
		
		logger.debug("[日志信息入库]" + logEntity.getDescription() + "[操作用户："
				+ operator + "]");
		
	}

	/**
	 * 对所有的切入点执行异常通知。日志打印
	 * 
	 * @author Lan
	 * @param jp
	 *            切入点
	 * @param ex
	 *            抛出异常
	 */
	@AfterThrowing(pointcut = "supportAOP()", throwing = "ex")
	public void doThrowing(JoinPoint jp, Throwable ex) {
		Logger log = Logger.getLogger(jp.getTarget().getClass());
		log.error(ex.getMessage(), ex);
	}

	private StringBuilder getLogDesc(StringBuilder logDesc, User u) {
		if (StringUtils.isNotBlank(u.getUsername()))
			logDesc.append(" 用户名=" + u.getUsername());
		if (StringUtils.isNotBlank(u.getChineseName()))
			logDesc.append(" 中文名=" + u.getChineseName());
		
		if (u.getRoleSet() != null && u.getRoleSet().size() > 0){
			logDesc.append(" 用户角色=");
			for(Role role : u.getRoleSet()){
				logDesc.append(role.getRoleName() + " ");
			}
		}
		
		if (StringUtils.isNotBlank(u.getPhone()))
			logDesc.append(" 手机=" + u.getPhone());
		if (StringUtils.isNotBlank(u.getEmail()))
			logDesc.append(" 邮箱=" + u.getEmail());
		if (StringUtils.isNotBlank(u.getDescription()))
			logDesc.append(" 备注=" + u.getDescription());
		return logDesc;
	}

}
